﻿using System;
using System.ComponentModel;
using System.Data.SqlServerCe;
using System.Globalization;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using SenseTimeTracker.BusinessLayer;
using SenseTimeTracker.Main;
using SenseTimeTracker.Misc;
using SenseTimeTracker.Properties;
using StedySoft.SenseSDK;
using StedySoft.SenseSDK.DrawingCE;
using Binder = SenseTimeTracker.Misc.Binder;

namespace SenseTimeTracker.TimeCards
{
	public class TimeCardsSliderPanel : CommonSliderPanel<TimeCard>
	{
		public enum PeriodFilter
		{
			[Description("TimeCardPeriodAll")]
			All,

			[Description("TimeCardPeriodThisWeek")]
			ThisWeek,

			[Description("TimeCardPeriodLastWeek")]
			LastWeek,

			[Description("TimeCardPeriodTwoWeeks")]
			TwoWeeks,

			[Description("TimeCardPeriodThisMonth")]
			ThisMonth,

			[Description("TimeCardPeriodLastMonth")]
			LastMonth,

			[Description("TimeCardPeriodTwoMonths")]
			TwoMonths,

			[Description("TimeCardPeriodThisYear")]
			ThisYear,

			[Description("TimeCardPeriodTLastYear")]
			LastYear,

			[Description("TimeCardPeriodTwoYears")]
			TwoYears,
		}

		public TimeCardsSliderPanel(SenseTimeTrackerForm form)
			: base(form, "TimeRecordSmallIcon.png", "TimeRecordLargeIcon.png", MenuEnty.All & ~MenuEnty.Duplicate)
		{
			sorting = Persistance.Instance.TimeRecordsSorting;
			sortColumns = SortColumn.Description | SortColumn.Date | SortColumn.Duration;
		}

		public override string Name { get { return Resources.PanelTimeCardsName; } }

		protected override void MenuItemNewEntry_Click(object sender, EventArgs e)
		{
			using (new DialogHelper(ownedForm))
			{
				TimeCardEditForm form = new TimeCardEditForm
				{
					TimeRecord = new TimeCard
					{
						StartDateTime = TimeCard.LatestTime(),
						FinalDateTime = Persistance.Instance.DefaultFinalTime,
						NewCard = true,
					},
					ConsiderCompletedTasks = true,
				};

				if (form.ShowDialog() == DialogResult.OK)
				{
					form.TimeRecord.Insert();
					Bind(senseListControl);
				}
			}
		}

		protected override void MenuItemEditEntry_Click(object sender, EventArgs e)
		{
			TimeCardDisplayItem item = senseListControl.FocusedItem as TimeCardDisplayItem;
			if (item != null)
			{
				if (EditTimeRecord(item.TimeCard.Id) == DialogResult.OK)
				{
					Bind(senseListControl);
				}
			}
		}

		protected override void MenuItemCopyEntry_Click(object sender, EventArgs e)
		{
			TimeCardDisplayItem item = senseListControl.FocusedItem as TimeCardDisplayItem;
			if (item != null)
			{
				Guid oldTimeRecordId = item.TimeCard.Id;
				Guid newTimeRecordId = TimeCard.Copy(oldTimeRecordId);
				if (EditTimeRecord(newTimeRecordId) != DialogResult.OK)
				{
					TimeCard.Delete(newTimeRecordId);
				}

				Bind(senseListControl);
			}
		}

		protected override void MenuItemRemoveEntry_Click(object sender, EventArgs e)
		{
			TimeCardDisplayItem item = senseListControl.FocusedItem as TimeCardDisplayItem;
			if (item != null)
			{
				if (SenseAPIs.SenseMessageBox.Show(Resources.DialogDeleteQuestion, Resources.DialogHeaderRemoveTimeCard, SenseMessageBoxButtons.YesNo) == DialogResult.Yes)
				{
					TimeCard.Delete(item.TimeCard.Id);
					Bind(senseListControl);
				}
			}
		}

		public override void BindFilter()
		{
			SensePanelComboItem clientFilterComboBox = new SensePanelComboItem();
			clientFilterComboBox.LabelText = string.Format("{0}:", Resources.ClientLabel);
			clientFilterComboBox.ShowSeparator = true;
			Binder.BindCombobox(clientFilterComboBox.Items, Guid.Empty, Guid.Empty, true, false);
			clientFilterComboBox.SelectedValue = Persistance.Instance.FilterForTimeCards.ClientFilter;
			clientFilterComboBox.OnSelectedValueChanged += clientFilterComboBox_OnSelectedValueChanged;
			if (clientFilterComboBox.SelectedIndex == -1)
			{
				clientFilterComboBox.SelectedIndex = 0;
				Persistance.Instance.FilterForTimeCards.ClientFilter = (Guid)clientFilterComboBox.Items[0].Value;
			}

			SensePanelComboItem projectFilterComboBox = new SensePanelComboItem();
			projectFilterComboBox.LabelText = string.Format("{0}:", Resources.ProjectLabel);
			projectFilterComboBox.ShowSeparator = true;
			Binder.BindCombobox(projectFilterComboBox.Items, (Guid)clientFilterComboBox.SelectedValue, Guid.Empty, true, false);
			projectFilterComboBox.SelectedValue = Persistance.Instance.FilterForTimeCards.ProjectFilter;
			projectFilterComboBox.OnSelectedValueChanged += projectFilterComboBox_OnSelectedValueChanged;
			if (projectFilterComboBox.SelectedIndex == -1)
			{
				projectFilterComboBox.SelectedIndex = 0;
				Persistance.Instance.FilterForTimeCards.ProjectFilter = (Guid)projectFilterComboBox.Items[0].Value;
			}

			SensePanelComboItem taskFilterComboBox = new SensePanelComboItem();
			taskFilterComboBox.LabelText = string.Format("{0}:", Resources.TaskLabel);
			taskFilterComboBox.ShowSeparator = true;
			Binder.BindCombobox(taskFilterComboBox.Items, (Guid)clientFilterComboBox.SelectedValue, (Guid)projectFilterComboBox.SelectedValue, true, false);
			taskFilterComboBox.SelectedValue = Persistance.Instance.FilterForTimeCards.ProjectFilter;
			taskFilterComboBox.OnSelectedValueChanged += taskFilterComboBox_OnSelectedValueChanged;
			if (taskFilterComboBox.SelectedIndex == -1)
			{
				taskFilterComboBox.SelectedIndex = 0;
				Persistance.Instance.FilterForTimeCards.TaskFilter = (Guid)taskFilterComboBox.Items[0].Value;
			}

			SensePanelComboItem periodFilterComboBox = new SensePanelComboItem();
			periodFilterComboBox.LabelText = string.Format("{0}:", Resources.PeriodLabel);
			periodFilterComboBox.ShowSeparator = true;
			periodFilterComboBox.OnSelectedValueChanged += periodFilterComboBox_OnSelectedValueChanged;
			foreach (KeyValuePair<object, string> periodFilter in EnumExtension.GetValues(typeof(PeriodFilter)))
			{
				periodFilterComboBox.Items.Add(new SensePanelComboItem.Item(periodFilter.Value, periodFilter.Key));
			}

			periodFilterComboBox.SelectedValue = Persistance.Instance.FilterForTimeCards.PeriodFilter;

			BindFilter(new SenseListControl.ISenseListItem[] { clientFilterComboBox, projectFilterComboBox, taskFilterComboBox, periodFilterComboBox }, Resources.TimeCardsFilterHeader);
		}

		/// <summary>
		/// Fills the adapter of the time record table
		/// and bind it to the list view
		/// </summary>
		public override void Bind(SenseListControl senseListControl)
		{
			base.Bind(senseListControl);
			filterItem.PrimaryText = string.Format(
				"{0}: {1}, {2}: {3}, {4}: {5}",
				Resources.ClientLabel,
				DatabaseManager.ClientName(Persistance.Instance.FilterForTimeCards.ClientFilter),
				Resources.ProjectLabel,
				DatabaseManager.ProjectName(Persistance.Instance.FilterForTimeCards.ProjectFilter),
				Resources.TaskLabel,
				DatabaseManager.TaskName(Persistance.Instance.FilterForTimeCards.TaskFilter));
			senseListControl.AddItem(new SensePanelDividerItem(string.Empty, Resources.TimeCardsExplanation));

			SqlCeCommand command = new SqlCeCommand(string.Empty, DatabaseManager.DbConnection);
			string selectStatement =
				"FROM TimeRecords " +
				"JOIN Tasks ON TimeRecords.taskId = Tasks.taskId " +
				"JOIN Projects ON Tasks.projectId = Projects.projectId " +
				"JOIN Clients ON Projects.clientId = Clients.clientId " +
				"WHERE ";

			if (Persistance.Instance.FilterForTimeCards.ClientFilter != DatabaseManager.AllClientsId)
			{
				selectStatement += "Projects.clientId = @clientId AND ";
				command.Parameters.Add("@clientId", Persistance.Instance.FilterForTimeCards.ClientFilter);
			}

			if (Persistance.Instance.FilterForTimeCards.ProjectFilter != DatabaseManager.AllProjectsId)
			{
				selectStatement += "Projects.projectId = @projectId AND ";
				command.Parameters.Add("@projectId", Persistance.Instance.FilterForTimeCards.ProjectFilter);
			}

			if (Persistance.Instance.FilterForTimeCards.TaskFilter != DatabaseManager.AllTasksId)
			{
				selectStatement += "Tasks.taskId = @taskId AND ";
				command.Parameters.Add("@taskId", Persistance.Instance.FilterForTimeCards.TaskFilter);
			}

			selectStatement += "TimeRecords.personId=@personId";
			command.Parameters.Add("@personId", Persistance.Instance.UserId);

			// filter records according to defined filters
			DateTime taskTime = DateTime.Now.Date - TimeSpan.FromDays((((int)DateTime.Now.Date.DayOfWeek - (int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek) + 7) % 7);

			switch (Persistance.Instance.FilterForTimeCards.PeriodFilter)
			{
				case PeriodFilter.ThisWeek:
					command.Parameters.Add("@timeFilterStart", taskTime);
					command.Parameters.Add("@timeFilterFinal", taskTime.AddDays(7));
					break;
				case PeriodFilter.LastWeek:
					command.Parameters.Add("@timeFilterStart", taskTime.AddDays(-7));
					command.Parameters.Add("@timeFilterFinal", taskTime);
					break;
				case PeriodFilter.TwoWeeks:
					command.Parameters.Add("@timeFilterStart", taskTime.AddDays(-7));
					command.Parameters.Add("@timeFilterFinal", taskTime.AddDays(7));
					break;
				case PeriodFilter.ThisMonth:
					taskTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
					command.Parameters.Add("@timeFilterStart", taskTime);
					command.Parameters.Add("@timeFilterFinal", taskTime.AddMonths(1));
					break;

				case PeriodFilter.LastMonth:
					taskTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
					command.Parameters.Add("@timeFilterStart", taskTime.AddMonths(-1));
					command.Parameters.Add("@timeFilterFinal", taskTime);
					break;

				case PeriodFilter.TwoMonths:
					taskTime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
					command.Parameters.Add("@timeFilterStart", taskTime.AddMonths(-1));
					command.Parameters.Add("@timeFilterFinal", taskTime.AddMonths(1));
					break;

				case PeriodFilter.ThisYear:
					taskTime = new DateTime(DateTime.Now.Year, 1, 1);
					command.Parameters.Add("@timeFilterStart", taskTime);
					command.Parameters.Add("@timeFilterFinal", taskTime.AddYears(1));
					break;

				case PeriodFilter.LastYear:
					taskTime = new DateTime(DateTime.Now.Year, 1, 1);
					command.Parameters.Add("@timeFilterStart", taskTime.AddYears(-1));
					command.Parameters.Add("@timeFilterFinal", taskTime);
					break;
				case PeriodFilter.TwoYears:
					taskTime = new DateTime(DateTime.Now.Year, 1, 1);
					command.Parameters.Add("@timeFilterStart", taskTime.AddYears(-1));
					command.Parameters.Add("@timeFilterFinal", taskTime.AddYears(1));
					break;
			}

			if (Persistance.Instance.FilterForTimeCards.PeriodFilter != PeriodFilter.All)
			{
				selectStatement += " AND timeRecordStartTime >= @timeFilterStart AND timeRecordFinalTime < @timeFilterFinal";
			}

			//adapter.SelectCommand.CommandText = "SELECT COUNT(*) " + selectStatement;
			//DatabaseManager.DbConnection.Open();
			//int num = (int)adapter.SelectCommand.ExecuteScalar();
			//DatabaseManager.DbConnection.Close();
			//buttonBackward.Enabled = firstTimeRecord > 0;
			//buttonForeward.Enabled = (num - firstTimeRecord) > maxTimeRecords;
			//listView.Columns[1].Width = listView.Columns[1].Width - (((num - firstTimeRecord) > 21) ? 24 : 0);
			//header.Headers[2].Width = listView.Columns[2].Width;

			//string orderStatement = " ORDER BY ";
			//switch (Persistance.Instance.TimeRecordSortColumn)
			//{
			//  case SortColumn.Date:
			//    orderStatement += "timeRecordStartTime";
			//    break;

			//  case SortColumn.Description:
			//    orderStatement += "description";
			//    break;

			//  case SortColumn.Duration:
			//    orderStatement += "duration";
			//    break;

			//  default:
			//    throw new NotSupportedException();
			//}

			//Persistance.Instance.TimeRecordSortOrder = SortOrder.Ascending;

			//switch (Persistance.Instance.TimeRecordSortOrder)
			//{
			//  case SortOrder.Ascending:
			//    command.CommandText += orderStatement + " ASC";
			//    break;
			//  case SortOrder.Descending:
			//    command.CommandText += orderStatement + " DESC";
			//    break;
			//  case SortOrder.Unsorted:
			//    break;
			//  default:
			//    throw new NotSupportedException();
			//}


			//adapter.Fill(firstTimeRecord, firstTimeRecord + maxTimeRecords, new[] { timeRecordsTable });
			//DataTable taskUsageTable = new DataTable();
			//adapter.SelectCommand.CommandText =
			//  "SELECT timeRecordId, taskId, timeRecordStartTime, timeRecordFinalTime " +
			//  "FROM TimeRecords " +
			//  "WHERE taskId IN (SELECT TimeRecords.taskId" + selectStatement + ") ORDER BY timeRecordStartTime";
			//adapter.Fill(taskUsageTable);

			//Dictionary<Guid, List<TaskUsage>> taskUsageList = new Dictionary<Guid, List<TaskUsage>>();
			//foreach (DataRow row in taskUsageTable.Rows)
			//{
			//  Guid taskId = (Guid)row["taskId"];
			//  if (!taskUsageList.ContainsKey(taskId))
			//  {
			//    taskUsageList[taskId] = new List<TaskUsage>();
			//  }

			//  taskUsageList[taskId].Add(
			//    new TaskUsage
			//    {
			//      TimeRecordId = (Guid)row["timeRecordid"],
			//      StartTime = (DateTime)row["timeRecordStartTime"],
			//      FinalTime = (DateTime)row["timeRecordFinalTime"],
			//    });
			//}

			command.CommandText = "SELECT timeRecordId, description, timeRecordStartTime, timeRecordFinalTime " + selectStatement;

			DatabaseManager.DbConnection.Open();
			SqlCeDataReader reader = command.ExecuteReader();
			List<TimeCard> timeRecords = new List<TimeCard>();
			while (reader.Read())
			{
				timeRecords.Add(new TimeCard
				{
					Id = (Guid)reader["timeRecordId"],
					Description = reader["description"].ToString(),
					StartDateTime = (DateTime)reader["timeRecordStartTime"],
					FinalDateTime = (DateTime)reader["timeRecordFinalTime"],
				});
			}

			command.CommandText =
				"SELECT timeRecordId, Tasks.taskId, timeRecordStartTime, timeRecordFinalTime, taskEstimate " +
				"FROM TimeRecords " +
				"JOIN Tasks ON Tasks.taskId = TimeRecords.taskId " +
				"WHERE Tasks.taskId IN (SELECT TimeRecords.taskId " + selectStatement + ") ORDER BY timeRecordStartTime";
			reader = command.ExecuteReader();

			var filteredTimeRecords = from timeRecord in timeRecords select timeRecord;
			SortFilter(ref filteredTimeRecords);
			foreach (TimeCard timeRecord in filteredTimeRecords)
			{
				senseListControl.AddItem(new TimeCardDisplayItem
				{
					TimeCard = timeRecord,
				});
			}

			Dictionary<Guid, Dictionary<Guid, TimeSpan>> taskUsageList = new Dictionary<Guid, Dictionary<Guid, TimeSpan>>();
			while (reader.Read())
			{
				Guid taskId = (Guid)reader["taskId"];
				TimeSpan duration = (DateTime)reader["timeRecordFinalTime"] - (DateTime)reader["timeRecordStartTime"];
				if (!taskUsageList.ContainsKey(taskId))
				{
					taskUsageList.Add(
						taskId,
						new Dictionary<Guid, TimeSpan>());
				}
			}

			DatabaseManager.DbConnection.Close();

			//foreach (DataRow row in timeRecordsTable.Rows)
			//{
			//  Guid taskId = (Guid)row["taskId"];
			//  Guid timeRecordId = (Guid)row["timeRecordId"];
			//  double totalDuration = 0.0;
			//  foreach (TaskUsage taskUsage in taskUsageList[taskId])
			//  {
			//    totalDuration += taskUsage.Duration;
			//    if (taskUsage.TimeRecordId == timeRecordId)
			//    {
			//      break;
			//    }
			//  }

			//  TimeSpan span = ((DateTime)row["timeRecordFinalTime"]) - ((DateTime)row["timeRecordStartTime"]);
			//  ListViewItem listViewItem = new ListViewItem(
			//    new[]
			//      {
			//        string.Format("{0:d}", row["timeRecordStartTime"]),
			//        row["description"].ToString(),
			//        ((span.Days * 24) + span.Hours).ToString("##00") + ":" + span.Minutes.ToString("00"),
			//        timeRecordId.ToString(),
			//      });

			//  if (totalDuration / 60.0 > (int)row["taskEstimate"])
			//  {
			//    listViewItem.BackColor = Persistance.Instance.Colors.OverbookedTasks.Color;
			//  }
			//  else if ((bool)row["taskCompleted"])
			//  {
			//    listViewItem.BackColor = Persistance.Instance.Colors.FinishedTasks.Color;
			//  }
			//  else
			//  {
			//    listViewItem.BackColor = row["taskColor"] == DBNull.Value ? Persistance.Instance.Colors.ActiveTasks.Color : Color.FromArgb((int)row["taskColor"]);
			//  }

			//  listView.Items.Add(listViewItem);
			//}
		}

		void periodFilterComboBox_OnSelectedValueChanged(object Sender, object Value)
		{
			Persistance.Instance.FilterForTimeCards.PeriodFilter = (TimeCardsSliderPanel.PeriodFilter)Value;
		}

		void clientFilterComboBox_OnSelectedValueChanged(object Sender, object Value)
		{
			Persistance.Instance.FilterForTimeCards.ClientFilter = (Guid)Value;
			BindFilter();
		}

		void projectFilterComboBox_OnSelectedValueChanged(object Sender, object Value)
		{
			Persistance.Instance.FilterForTimeCards.ProjectFilter = (Guid)Value;
			BindFilter();
		}

		void taskFilterComboBox_OnSelectedValueChanged(object Sender, object Value)
		{
			Persistance.Instance.FilterForTimeCards.TaskFilter = (Guid)Value;
			BindFilter();
		}

		/// <summary>
		/// Prepares the edit dialog and opens it
		/// </summary>
		/// <param name="timeRecordId">The timerecords Id to be edited</param>
		private DialogResult EditTimeRecord(Guid timeRecordId)
		{
			DialogResult dialogResult = DialogResult.Cancel;

			using (new DialogHelper(ownedForm))
			{
				TimeCardEditForm form = new TimeCardEditForm
				{
					TimeRecord = TimeCard.GetTimeCard(timeRecordId),
					ConsiderCompletedTasks = false,
				};

				if (form.ShowDialog() == DialogResult.OK)
				{
					form.TimeRecord.Update();
					dialogResult = DialogResult.OK;
				}
			}

			return dialogResult;
		}
	}
}
